// ValidationAspects
// Written by Mike Saunders
// Released under Microsoft Public License (Ms-PL)
using System;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
using ValidationAspects;

namespace TestValidationAspects
{
	[TestFixture]
	public class TestValidationException
	{
		[Test]
		public void Test_Constructor_string_param()
		{
			const string message = "the message";
			Assert.AreEqual(message, new ValidationException(message).Message);
		}

		[Test]
		public void Test_Constructor_string_Exception_parama()
		{
			const string message = "the message";
			Exception innerException = new Exception();

			ValidationException exception = new ValidationException(message, innerException);
			Assert.AreEqual(message, exception.Message);
			Assert.AreSame(innerException, exception.InnerException);
		}

		[Test]
		public void Test_default_get_Context()
		{
			Assert.IsNull(new ValidationException().Context);
		}

		[Test]
		public void Test_get_set_Context()
		{
			IValidationContext context = new MockValidationContext();
			ValidationException exception = new ValidationException();
			exception.SetContext(context);
			Assert.AreSame(context, exception.Context);
		}

		[Test]
		public void Test_Messages()
		{
			string[] messages = new ValidationException("message").Messages.ToArray();
			Assert.AreEqual(1, messages.Count());
			Assert.AreEqual("message", messages[0]);
		}

		[Test]
		public void Test_GetValidationTargetName_returns_Value_for_null_Context()
		{
			Assert.AreEqual("Value", new ValidationException().GetValidationTargetName());
		}

		[Test]
		public void Test_GetValidationTargetName_returns_Property_Name_for_property_Context()
		{
			ValidationException exception = new ValidationException();
			PropertyInfo property = TypeOf<AClass>.GetProperty(x => x.AProperty);
			exception.SetContext(new MockValidationContext {Property = property});

			Assert.AreEqual(property.Name, exception.GetValidationTargetName());
		}

		[Test]
		public void Test_GetValidationTargetName_returns_Parameter_info_for_parameter_Context()
		{
			ValidationException exception = new ValidationException();
			Type type = typeof(AClass);
			MethodInfo method = type.GetMethod("AMethod");
			ParameterInfo parameter = method.GetParameters()[0];
			exception.SetContext(new MockValidationContext{Type = type, Method = method, Parameter = parameter});

			Assert.AreEqual(string.Format("{0}.{1}.{2}", type.Name, method.Name, parameter.Name), exception.GetValidationTargetName());
		}

		[Test]
		public void Test_GetValidationTargetName_returns_Type_Name_for_type_Context()
		{
			ValidationException exception = new ValidationException();
			Type type = typeof(AClass);
			exception.SetContext(new MockValidationContext{Type = type});

			Assert.AreEqual(type.Name, exception.GetValidationTargetName());
		}

		#region Mocks
		public class AClass
		{
			public string AProperty { get; set; }
			public void AMethod(string aParameter) { }
		}
		#endregion
	}
}